<?php

(function () {
    $scan = function ($dir, $namespace, $initPrefix) use (&$scan) {
        $h = \opendir($dir);
        while (false !== $file = \readdir($h)) {
            if (\in_array($file, ['.', '..'])) {
                continue;
            }

            $filename = "$dir/$file";

            if (\is_dir($filename)) {
                $scan($filename, "$namespace\\$file", $initPrefix);
                continue;
            }

            $class = \str_replace('.php', '', "$namespace\\$file");

            $refClass = new ReflectionClass($class);

            $classAttrs = $refClass->getAttributes(\_Route::class);
            if ($classAttrs) {
                $classAttr = $classAttrs[0];
                /** @var \_Route $classAttrObj */
                $classAttrObj = $classAttr->newInstance();

                if ($classAttrObj->middleware) {
                    $groupReg = \Illuminate\Support\Facades\Route::middleware($classAttrObj->middleware);
                }
                if ($classAttrObj->name) {
                    if (isset($groupReg)) {
                        $groupReg->name($classAttrObj->name);
                    } else {
                        $groupReg = \Illuminate\Support\Facades\Route::name($classAttrObj->name);
                    }
                }
            }

            $refMethods = $refClass->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED);

            foreach ($refMethods as $refMethod) {
                if (
                    $refMethod->isStatic()
                    || $refMethod->isAbstract()
                    || $refMethod->isConstructor()
                    || $refMethod->isDestructor()
                    || !$refMethod->isUserDefined()
                    || $refMethod->getDeclaringClass()->getName() != $refClass->getName()
                ) {
                    continue;
                }

                $methodAttrs = $refMethod->getAttributes(\_Route::class);

                if (!$methodAttrs) {
                    continue;
                }

                $uri = \substr($refClass->getName(), \strlen($initPrefix));

                if (\str_ends_with($uri, 'Controller')) {
                    $uri = \substr($uri, 0, \strlen($uri) - 10);
                }

                $uri = \str_replace('\\', '/', $uri);

                // 如果是`index`，则省略
                if ($refMethod->getName() != 'index') {
                    $uri = $uri . '/' . $refMethod->getName();
                }

                if ($uri == 'Index') {
                    $uri = '/';
                } elseif (str_ends_with($uri, '/Index')) {
                    $uri = substr($uri, 0, strlen($uri) - 6);
                }

                // 只能允许一个 _Route
                $routeAttr = $methodAttrs[0];

                /** @var \_Route $attrObj */
                $attrObj = $routeAttr->newInstance();

                if ($attrObj->params) {
                    $uri = "$uri/$attrObj->params";
                }

                $regRoute = function () use ($attrObj, $uri, $refMethod) {
                    $route = \Illuminate\Support\Facades\Route::match(
                        $attrObj->method,
                        $uri,
                        [$refMethod->getDeclaringClass()->getName(), $refMethod->getName()],
                    );
                    if ($attrObj->name) {
                        $route->name($attrObj->name);
                    }
                    if ($attrObj->middleware) {
                        $route->middleware($attrObj->middleware);
                    }
                    if ($attrObj->withoutMiddleware) {
                        $route->withoutMiddleware($attrObj->withoutMiddleware);
                    }
                    if ($attrObj->where) {
                        $route->where($attrObj->where);
                    }
                };

                if (isset($groupReg)) {
                    $groupReg->group($regRoute);
                } else {
                    $regRoute();
                }
            }
        }
        closedir($h);
    };

    $prefixes = [
        'App\Http\Controllers',
    ];

    /** @var \Composer\Autoload\ClassLoader $classLoader */
    $classLoader = \app('classLoader');

    foreach ($classLoader->getPrefixesPsr4() as $pre => $paths) {
        foreach ($prefixes as $p) {
            if (\str_starts_with($p, $pre)) {
                $subPath = \str_replace('\\', '/', \substr($p, \strlen($pre)));
                foreach ($paths as $path) {
                    if (\is_dir("$path/$subPath")) {
                        $dir = "$path/$subPath";

                        $scan($dir, $p, "$p\\");
                    }
                }
            }
        }
    }
})();
